import { Injectable, Inject } from '@angular/core';
import { environment } from '../../environments/environment';
import { StorageService, SESSION_STORAGE } from 'ngx-webstorage-service';
import { CookieService } from 'ngx-cookie-service';
import { MemberVo } from '../model/member-vo';
import { UtilService } from './util.service';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { from, race, Observable } from 'rxjs';
@Injectable({
  providedIn: 'root'
})
export class MemberStorageService {
  //cookie中的key:全局设置
  private cookieKey: string = environment.cookieKey;
  //登录成功后cookie的值,每个会员每次都需不一致
  //需要从一端登录后,到另一端也是在线吗?
  private cookieValueTempate: string = 'member#%UID%#%RND%';
  //npm install ngx-webstorage-service  @see://github.com/dscheerens/ngx-webstorage-service
  //npm install ngx-cookie-service @see://www.npmjs.com/package/ngx-cookie-service
  /**
   * 会员存储服务
   */
  constructor(private http: HttpClient,private util: UtilService, private cookieService: CookieService, @Inject(SESSION_STORAGE) private storage: StorageService) { }
  /**
   * 持久化/缓存会员实例
   * @param activeMember 
   */
  public set(activeMember: MemberVo): void {
    if (activeMember && activeMember.id > 0) {
      //保存
      let skey = this.cookieValueTempate.replace('%UID%', activeMember.id + '').replace('%RND%', this.util.randomAlphaNumeric(6) + '');
      //BASE64 @see://developer.mozilla.org/en-US/docs/Glossary/Base64
      let b64v = btoa(skey);
      let cookieOpt: any = { expires: environment.cookieExpires, path: environment.cookiePath, secure: environment.cookieSecure };
      if (null !== environment.cookieDomain) {
        cookieOpt.domain = environment.cookieDomain;
      }
      this.cookieService.set(this.cookieKey, b64v, cookieOpt); //Number of days until the cookies expires or an actual `Date`
      this.storage.set(skey, activeMember);
    }
  }
  /**
   * 更新缓存中的个性签名或头像
   * @param uid 会员ID
   * @param updateValue 支持的key=[signature,avatar]
   * @returns 更新成功返回true
   */
  public updateStorage(uid: number, updateValue: { signature?: string, avatar?: string }): boolean {
    if (!this.isOnline()) {
      return false;
    }
    let b64v = this.cookieService.get(this.cookieKey);
    if (!b64v) {
      return false;
    }
    let skey = atob(b64v);
    let cacheMember: MemberVo = this.storage.get(skey);
    if (updateValue.signature) {
      cacheMember.signature = updateValue.signature;
    }
    if (updateValue.avatar) {
      cacheMember.avatar = updateValue.avatar;
    }
    this.storage.set(skey, cacheMember);
    return true;

  }
  /**
   * 当前在线状态
   * @deprecated 可能存在注销后,还是返是返回true
   * @returns 在线返回true
   */
  private isOnline(): boolean {
    return this.cookieService.check(this.cookieKey)
  }

  /**
   * 从Cookie中取uid
   * @returns 不在线时返回-1,在线取值失败时返回0
   */
  public getUid(): number {
    if (!this.isOnline()) {
      return -1;
    }
    let b64v = this.cookieService.get(this.cookieKey);
    let sdKey = atob(b64v);
    try {
      return parseInt(sdKey.split('#')[1], 10);
    } catch (e) {
      return 0;
    }
  }

  /**
   * 返回当前的会员实例
   * @returns 不在线时返回null,本地缓存无命中返回null,在线&&本地缓存命中返回实例
   */
  public get(): MemberVo | null {
    if (!this.isOnline()) {
      return null;
    }
    let b64v = this.cookieService.get(this.cookieKey);
    let sdKey = atob(b64v);
    if (this.storage.has(sdKey)) {
      return this.storage.get(sdKey);
    }
    return null;
  }

  /**
   * 清空持久化/缓存会员实例
   * 从Cookie中删除,从本地缓存中删除
   */
  public remove(): void {
    if (this.isOnline()) {
      let b64v = this.cookieService.get(this.cookieKey);
      this.cookieService.delete(b64v);
      this.storage.remove(atob(b64v))
    }
  }
  /**
   * 将编码后的头像地址转换为本地头像
   * @param encodeAvatarURL 
   * @returns 若参数不可用返回null,若编码地址不是本地格式返回null
   */
  public decodeLocalAvatar(encodeAvatarURL: string): string | null {
    //console.log('[SideMemberPanel-CMP]current member avatar: ' + encodeAvatarURL);
    if (!encodeAvatarURL || encodeAvatarURL.length === 0) {
      return null;
    }
    if (!encodeAvatarURL.startsWith('avtar://local')) {
      return null;
    }
    return 'assets/avatar' + encodeAvatarURL.substring(13);
  }
  /**
   * 查看客户端的IP地址
   * 用于竞争的 Observables 源，以比试哪个 Observable 会首先发出项。
   * 竞赛:getRemoteClient(), getAppClient()
   */
  public getIpCliente(): Observable<string> {
    //return race([this.getRemoteClient(), this.getAppClient()]);
    return this.getAppClient();
  }
  /**
   * 查看客户端的IP地址
   * 请求的地址:api.ipify.org,永远返回的是公网ip
   * @deprecated
   */
  public getRemoteClient(): Observable<string> {
    let r:Observable<string> = this.http.jsonp('http://api.ipify.org/?format=jsonp&callback=JSONP_CALLBACK', 'callback').pipe(map((res:Object)=>{
      //console.log(typeof res);//{ip: "27.216.163.203"}
      let jsV = JSON.parse(JSON.stringify(res));
      return jsV.ip;
    }));
    return r;
  }
  /**
   * 查看客户端的IP地址
   * 请求的地址:rest.test.com/member/ip/query,内部程序返回:127.0.0.1
   */
  public getAppClient(): Observable<string> {
    let restAPI:string  = environment.restURI + '/member/ip/query'
    return this.http.get(restAPI).pipe(map((res:Object)=>{
      //console.log(res); //{ip: "127.0.0.1"}
      let jsV = JSON.parse(JSON.stringify(res));
      return jsV.ip;
    }));
  }
}
